/**
 * 金额转中文
 * 思路：
 *                             个
 *      十     百      千       万
 *      十万   百万    千万      亿
 *      十亿   百亿    千亿      万亿
 *
 *                              0
 *      1      2       3        4
 *      5      6       7        8
 *      9      10      11       12
 *
 * 计算步骤
 * 1. 获取当前数值大小
 * 2. 排除个位后 数值按个，十，百，千有规律的重复 所以计算其和4的余数 pos % 4
 * 3. 补充最大单位，例如上面第三，四行的万和亿
 *    pos = 0 ~ 3 没有最大单位
 *    pos = 4 ~ 7 最大单位是万
 *    pos = 8 ~ 11 最大单位是亿
 *    pos / 4 的整数就是最大单位
 */
export function getAmountChinese(val) {
  const amount = +val;
  if (Number.isNaN(amount) || amount < 0) return "";
  const NUMBER = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
  const N_UNIT1 = ["", "拾", "佰", "仟"];
  const N_UNIT2 = ["", "万", "亿", "万亿"];
  const D_UNIT = ["角", "分", "厘", "毫"];
  let [integer, decimal] = amount.toString().split(".");
  if (integer && integer.length > 12) return "金额过大无法计算";
  let res = "";
  // 整数部分
  if (integer) {
    for (let i = 0, len = integer.length; i < len; i++) {
      const num = integer.charAt(i);
      const isZero = num === "0";
      const pos = len - i - 1; // 排除个位后 所处的索引位置
      const isMaxUniPos = pos % 4 === 0;
      const isZeroNext = integer.charAt(i + 1) === "0";
      if (!(isZero && (isZeroNext || isMaxUniPos))) {
        // 当前位 等于 0 且下一位也等于 0 则可跳过计算
        res += NUMBER[num];
        if (!isZero) res += N_UNIT1[pos % 4];
      }
      if (isMaxUniPos) {
        res += N_UNIT2[Math.floor(pos / 4)];
      }
    }
    res += "圆";
  }
  // 小数部分
  if (parseInt(decimal)) {
    const loopCount = Math.min(decimal.length, 4);
    for (let i = 0; i < loopCount; i++) {
      const num = decimal.charAt(i);
      if (num !== "0") res += NUMBER[num] + D_UNIT[i];
    }
  } else {
    res += "整";
  }
  return res;
}

/**
 * 计算两个时间差经历的时间的文字描述
 * @param {*} timestamp - 毫秒
 */
export const timeCalculate = (start, end) => {
  const label = ["分钟", "小时", "天", "月", "年"];
  const unit = [60, 60, 24, 30, 12];
  let restTime = Math.floor((end - start) / 1000);
  let res = "";
  for (let i = 0, len = unit.length; i < len; i++) {
    const pos = len - i; // 从年开始算，分钟换算成年 === Math.pow(60, 4)
    const temp = unit.slice(0, pos).reduce((p, c) => p * c, 1);
    const time = Math.floor(restTime / temp);
    time > 0 && (res += time + label[pos - 1]);
    restTime -= time * temp;
  }
  return res;
};

/**
 * 简易防抖函数
 * @param {Function} func -防抖目标函数
 * @param {Number}} gap - 防抖时间间隔
 */
export const debounce = (func, gap) => {
  let timer;
  return function () {
    timer && clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, arguments);
    }, gap);
  };
};
/**
 * 下划线转驼峰
 * @param {String} name - 字符串
 */
export const toHump = (name) =>
  name.replace(/\_(\w)/g, function (all, letter) {
    return letter.toUpperCase();
  });
/**
 * 将用户输入的连续单个数字合并为一个数
 * @param {Array} expressions - 记录计算表达式的数组
 * @returns {Array} 新的数组
 */
export const mergeNumberOfExps = (expressions) => {
  const res = [];
  const isNumChar = (n) => /^[\d|\.]$/.test(n);
  for (let i = 0; i < expressions.length; i++) {
    if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) {
      res[res.length - 1] += expressions[i];
      continue;
    }
    res.push(expressions[i]);
  }
  return res;
};
/**
 * 校验表达式是否符合计算法则
 * @param {Array} expressions - 合并数字后的表达式数组
 * @returns {Boolean}
 */
export const validExp = (expressions, mergeNum = true) => {
  const temp = mergeNum ? mergeNumberOfExps(expressions) : expressions;
  const arr = temp.filter((t) => !"()".includes(t));
  // 去括号后 length应该为奇数  并且第一个字符和最后一个字符应该为数字而非计算符号
  if (
    temp.length % 2 === 0 ||
    arr.length % 2 === 0 ||
    Number.isNaN(+arr[0]) ||
    Number.isNaN(+arr[arr.length - 1])
  ) {
    return false;
  }
  for (let i = 0; i < arr.length - 1; i += 2) {
    if (typeof +arr[i] !== "number" || !Number.isNaN(+arr[i + 1])) return false;
  }
  return true;
};

/**
 * 中缀转后缀（逆波兰 Reverse Polish Notation）
 * @param {Array} exps - 中缀表达式数组
 */
export const toRPN = (exps) => {
  const s1 = []; // 符号栈
  const s2 = []; // 输出栈
  const getTopVal = (stack) =>
    stack.length > 0 ? stack[stack.length - 1] : null;
  const levelCompare = (c1, c2) => {
    const getIndex = (c) => ["+-", "×÷", "()"].findIndex((t) => t.includes(c));
    return getIndex(c1) - getIndex(c2);
  };
  exps.forEach((t) => {
    if (typeof t === "string" && Number.isNaN(Number(t))) {
      // 是符号
      if (t === "(") {
        s1.push(t);
      } else if (t === ")") {
        let popVal;
        do {
          popVal = s1.pop();
          popVal !== "(" && s2.push(popVal);
        } while (s1.length && popVal !== "(");
      } else {
        let topVal = getTopVal(s1);
        if (!topVal) {
          // s1 为空 直接push
          s1.push(t);
        } else {
          while (topVal && topVal !== "(" && levelCompare(topVal, t) >= 0) {
            // 优先级 >= t 弹出到s2
            s2.push(s1.pop());
            topVal = getTopVal(s1);
          }
          s1.push(t);
        }
      }
      return;
    }
    s2.push(t); // 数字直接入栈
  });
  while (s1.length) {
    s2.push(s1.pop());
  }
  return s2;
};
/**
 * 计算后缀表达式的值
 * @param {Array} rpnExps - 后缀表达式
 */
export const calcRPN = (rpnExps) => {
  rpnExps = rpnExps.concat();
  const calc = (x, y, type) => {
    let a1 = Number(x),
      a2 = Number(y);
    switch (type) {
      case "+":
        return a1 + a2;
      case "-":
        return a1 - a2;
      case "×":
        return a1 * a2;
      case "÷":
        return a1 / a2;
    }
  };
  for (let i = 2; i < rpnExps.length; i++) {
    if ("+-×÷".includes(rpnExps[i])) {
      let val = calc(rpnExps[i - 2], rpnExps[i - 1], rpnExps[i]);
      rpnExps.splice(i - 2, 3, val);
      i = i - 2;
    }
  }
  return rpnExps[0];
};
